#include "xdgvlc.h"
#include <QWidget>
#include <QDebug>

// 构造函数
xdgVLC::xdgVLC(QObject *parent)
    : QObject{parent},
    m_libvlc_instance(nullptr),
    m_libvlc_media(nullptr),
    m_libvlc_media_player(nullptr),
    m_isMediaInfoAvailable(false)
{
    // 构造函数的核心职责是确保对象创建后处于一个有效的状态
    if (!vlcInit()) {
        qWarning() <<"VLC engine failed to initialize.";
    }

}

// 析构函数
xdgVLC::~xdgVLC()
{
    // 释放资源的顺序与创建顺序相反，确保安全的清理：m_libvlc_media_player -> m_libvlc_media -> m_libvlc_instance
    // 清理播放器和媒体资源
    cleanupPlayer();

    // 最后释放VLC实例
    if (m_libvlc_instance) {
        libvlc_release(m_libvlc_instance);
    }


}

// 设置媒体
bool xdgVLC::setMedia(const QString &mediaPathOrUrl)
{
    // 1. 调用统一的清理函数
    cleanupPlayer();

    // 2. 根据输入是URL还是本地路径，创建新的媒体对象
    if (mediaPathOrUrl.startsWith("http", Qt::CaseInsensitive) || mediaPathOrUrl.startsWith("rtsp", Qt::CaseInsensitive)) {
        m_libvlc_media = libvlc_media_new_location(m_libvlc_instance, mediaPathOrUrl.toUtf8().constData());
    } else {
        m_libvlc_media = libvlc_media_new_path(m_libvlc_instance, mediaPathOrUrl.toUtf8().constData());
    }

    if (!m_libvlc_media) {
        emit errorOccurred(QString("Failed to create media object for: %1").arg(mediaPathOrUrl));
        return false;
    }


    // 3. 基于新的媒体对象创建播放器
    m_libvlc_media_player = libvlc_media_player_new_from_media(m_libvlc_media);

    if (!m_libvlc_media_player) {
        emit errorOccurred("Failed to create media player from media object.");
        libvlc_media_release(m_libvlc_media); // 清理刚才创建的媒体对象
        m_libvlc_media = nullptr;
        return false;
    }


    // 注册解析视频元数据事件监听，让libvlc在后台开始解析媒体信息
    libvlc_event_manager_t *em = libvlc_media_event_manager(m_libvlc_media);
    libvlc_event_attach(em, libvlc_MediaParsedChanged, handleVlcEvent, this);
    libvlc_media_parse_with_options(m_libvlc_media, libvlc_media_parse_local, 60000); // 开始异步解析


    // --- 为播放器附加事件监听 ---
    // 从播放器对象那里，获取其事件管理器的“名片”
    libvlc_event_manager_t *player_em = libvlc_media_player_event_manager(m_libvlc_media_player);

    // 订阅“正在播放”事件。当调用 play() 后，播放器成功开始渲染第一帧时触发。
    libvlc_event_attach(player_em, libvlc_MediaPlayerPlaying, handleVlcEvent, this);

    // 订阅“暂停”事件。当播放器从播放状态进入暂停状态时触发。
    libvlc_event_attach(player_em, libvlc_MediaPlayerPaused, handleVlcEvent, this);

    // 订阅“停止”事件。当用户调用 stop() 后触发，位置通常会归零。
    libvlc_event_attach(player_em, libvlc_MediaPlayerStopped, handleVlcEvent, this);

    // 订阅“播放结束”事件。当媒体正常播放到末尾时触发。
    libvlc_event_attach(player_em, libvlc_MediaPlayerEndReached, handleVlcEvent, this);

    // 订阅“时间变化”事件。用于获取精确的毫秒级播放时间，非常适合更新时间标签 (e.g., "01:23 / 04:56")。
    libvlc_event_attach(player_em, libvlc_MediaPlayerTimeChanged, handleVlcEvent, this);

    // 订阅“位置变化”事件。用于获取0.0到1.0之间的播放进度，是更新进度条的最佳事件。
    libvlc_event_attach(player_em, libvlc_MediaPlayerPositionChanged, handleVlcEvent, this);
    // ------------------------------------

    return true;
}

// 设置视频输出窗口
void xdgVLC::setVideoWidget(QWidget *videoWidget)
{
    if (!m_libvlc_media_player || !videoWidget) { return; }
    libvlc_media_player_set_hwnd(m_libvlc_media_player, (void*)videoWidget->winId()); // 将Qt的窗口ID（WId）传递给libvlc

}

// 播放
void xdgVLC::play()
{
    if (m_libvlc_media_player) {
        libvlc_media_player_play(m_libvlc_media_player);
    }
}

// 暂停
void xdgVLC::pause()
{
    if (m_libvlc_media_player) {
        libvlc_media_player_pause(m_libvlc_media_player);
    }
}

// 停止
void xdgVLC::stopAsync ()
{
    // [!! 关键修复：防止竞态条件 !!]

    // 1. 检查是否真的有播放器需要停止。
    //    如果 m_libvlc_media_player 已经是 nullptr (例如被连续调用)，
    //    我们什么都不做，直接返回。
    if (!m_libvlc_media_player) {
        //  emit stopped(); // 可以在这里发射，以确保UI状态一致
        return;
    }

    // 2. [捕获] 将当前的成员指针复制到局部变量中。
    //    这是我们要释放的“旧”播放器和“旧”媒体。
    libvlc_media_player_t *p_player_to_release = m_libvlc_media_player;
    libvlc_media_t *p_media_to_release = m_libvlc_media;

    // 3. [隔离] 立即将成员变量设为 nullptr。
    //    这样，即使 startPlayer() -> setMedia() 立刻被调用，
    //    setMedia() 中的 cleanupPlayer() 也会看到 nullptr 而安全跳过。
    m_libvlc_media_player = nullptr;
    m_libvlc_media = nullptr;

    // 4. 从“旧”播放器中分离所有事件
    libvlc_event_manager_t *em = libvlc_media_player_event_manager(p_player_to_release);
    if(em){
        libvlc_event_detach(em, libvlc_MediaPlayerPlaying, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerPaused, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerStopped, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerEndReached, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, handleVlcEvent, this);
    }

    // 5. 从“旧”媒体中分离事件
    if (p_media_to_release) {
        libvlc_event_manager_t *media_em = libvlc_media_event_manager(p_media_to_release);
        if (media_em) {
            libvlc_event_detach(media_em, libvlc_MediaParsedChanged, handleVlcEvent, this);
        }
    }


    // 6. 停止“旧”播放器
#if defined(LIBVLC_VERSION_MAJOR) && LIBVLC_VERSION_MAJOR >= 4
    libvlc_media_player_stop_async(p_player_to_release);
#else
    libvlc_media_player_stop(p_player_to_release);
#endif

    // 7. [安全释放] 启动定时器，释放我们“捕获”的局部指针，
    //    而不是访问可能已更改的成员变量。
    QTimer::singleShot(100, this, [this, p_player_to_release, p_media_to_release]() {

        // 这里的 p_player_to_release 和 p_media_to_release
        // 引用的是第(2)步中捕获的指针。
        if (p_player_to_release) {
            libvlc_media_player_release(p_player_to_release);
        }

        if (p_media_to_release) {
            libvlc_media_release(p_media_to_release);
        }

        // [!! 修复 !!]
        // 移除了对 m_isMediaInfoAvailable 和 m_mediaInfo 的重置。
        // 这些状态的重置必须由 setMedia -> cleanupPlayer 同步完成，
        // 以避免污染新播放器的状态。

        emit stopped();  // 确保发出停止信号
    });
}

// 跳转到指定的播放位置（百分比）
void xdgVLC::setPosition(float position)
{
    if (m_libvlc_media_player) {
        // 在设置前，最好检查一下范围，防止传入无效值
        if (position < 0.0f) position = 0.0f;
        if (position > 1.0f) position = 1.0f;
        libvlc_media_player_set_position(m_libvlc_media_player, position);
    }
}

// 快退
void xdgVLC::rewind(int milliseconds)
{
    // 确保播放器实例存在
    if (m_libvlc_media_player) {
        // 1. 获取当前的播放时间（单位：毫秒）libvlc_time_t 是一个64位整型，用于精确表示时间
        libvlc_time_t currentTime = libvlc_media_player_get_time(m_libvlc_media_player);

        // 2. 计算出目标时间
        libvlc_time_t newTime = currentTime - milliseconds;

        // 3. 边界检查：确保目标时间不会是负数
        if (newTime < 0) {
            newTime = 0; // 如果是负数，则直接跳到视频开头
        }

        // 4. 设置新的播放时间
        libvlc_media_player_set_time(m_libvlc_media_player, newTime);
    }
}

// 快进
void xdgVLC::forward(int milliseconds)
{
    // 确保播放器实例存在
    if (m_libvlc_media_player) {
        // 1. 获取当前的播放时间
        libvlc_time_t currentTime = libvlc_media_player_get_time(m_libvlc_media_player);

        // 2. 直接设置目标时间（libvlc会自动处理超出总时长的情况，会跳到结尾）
        libvlc_media_player_set_time(m_libvlc_media_player, currentTime + milliseconds);
    }
}

// 设置音量
void xdgVLC::setVolume(int volume)
{
    if (m_libvlc_media_player) {
        libvlc_audio_set_volume(m_libvlc_media_player, volume); // libvlc_audio_set_volume 是一个全局函数，但操作的是播放器
    }
}

// 设置播放状态
void xdgVLC::setRate(float rate)
{
    if (m_libvlc_media_player) {
        // libvlc_media_player_set_rate 会返回一个值，-1表示失败
        libvlc_media_player_set_rate(m_libvlc_media_player, rate);
    }
}


/**
 * @brief 强制VLC使用特定的宽高比字符串。
 */
void xdgVLC::setAspectRatio(const QString &ratio)
{
    if (m_libvlc_media_player) {
        // 这会强制视频拉伸以匹配该比例
        libvlc_video_set_aspect_ratio(m_libvlc_media_player, ratio.toUtf8().constData());
    }
}


// 检查媒体信息是否已成功解析并可用。
bool xdgVLC::isMediaInfoAvailable() const
{
    return m_isMediaInfoAvailable;
}

// 获取已解析的媒体信息。
MediaInfo xdgVLC::getMediaInfo() const
{
    return m_mediaInfo;
}

// 获取当前音量值
int xdgVLC::getVolume() const
{
    if (m_libvlc_media_player) {
        return libvlc_audio_get_volume(m_libvlc_media_player);
    }
    return 0; // 如果播放器不存在，返回0
}


// 获取当前播放状态
PlayerState xdgVLC::getState() const
{
    // 首先，检查播放器是否存在。如果不存在，直接返回错误状态。
    if (!m_libvlc_media_player) {
        return PlayerState::Error;
    }

    // 调用 libvlc 的函数获取原始的 libvlc_state_t 状态
    libvlc_state_t state = libvlc_media_player_get_state(m_libvlc_media_player);

    // 使用 switch 语句将 libvlc 的状态安全地转换为我们自己的 PlayerState
    switch (state) {
    case libvlc_NothingSpecial: return PlayerState::NothingSpecial;
    case libvlc_Opening:        return PlayerState::Opening;
    case libvlc_Buffering:      return PlayerState::Buffering;
    case libvlc_Playing:        return PlayerState::Playing;
    case libvlc_Paused:         return PlayerState::Paused;
    case libvlc_Stopped:        return PlayerState::Stopped;
    case libvlc_Ended:          return PlayerState::Ended;
    case libvlc_Error:          return PlayerState::Error;
    // default 分支用于处理未来 libvlc 可能新增的未知状态，增强代码的健壮性
    default:                    return PlayerState::Error;
    }
}


// 初始化VLC实例（私有）
bool xdgVLC::vlcInit()
{
    // 为嵌入式播放器设置一些默认的启动参数
    const char* const vlc_args[] = {
        "--ignore-config",        // 不加载VLC的配置文件，避免受用户本地VLC配置的干扰
        "--quiet",                // 在控制台输出更少的日志信息
        "--no-video-title-show",  // 播放时不自动在视频窗口顶部显示媒体标题
    };
    int argc = sizeof(vlc_args) / sizeof(vlc_args[0]);

    m_libvlc_instance = libvlc_new(argc, vlc_args);

    if (m_libvlc_instance == nullptr) {
        // emit errorOccurred("Failed to create libvlc instance. Check if VLC is installed correctly.");
        // 构造函数完成之前，它的信号槽机制可能还没有完全准备好，此时发射信号是不安全的，
        qWarning() << "Failed to create libvlc instance. Check if VLC is installed correctly.";
        return false;
    }
    return true;
}

// 获取元数据的辅助函数（私有）
QString xdgVLC::getMeta(libvlc_meta_t metaType)
{
    if (!m_libvlc_media) { return QString(); }

    char *metaData = libvlc_media_get_meta(m_libvlc_media, metaType);  // libvlc会为自动分配内存来存储元数据字符串

    QString result;
    if (metaData) {
        result = QString::fromUtf8(metaData);
        libvlc_free(metaData); // 使用libvlc_free来释放它分配的内存，防止泄漏
    }
    return result;
}

// 处理元数据变化的成员函数，获取信息到成员变量里（私有）
void xdgVLC::processMediaMetaChanged()
{
    if (!m_libvlc_media) {
        // media 已被释放或尚未设置，直接返回
        return;
    }

    MediaInfo info; // 创建临时info对象

    // 1. 获取时长
    info.duration = libvlc_media_get_duration(m_libvlc_media);
    info.durationText = QTime::fromMSecsSinceStartOfDay (info.duration).toString ("hh:mm:ss");

    // 2. 使用辅助函数获取其他字符串信息
    info.title       = getMeta(libvlc_meta_Title);
    info.copyright   = getMeta(libvlc_meta_Copyright);
    info.description = getMeta(libvlc_meta_Description);
    info.date        = getMeta(libvlc_meta_Date);
    info.url         = getMeta(libvlc_meta_URL);
    info.language    = getMeta(libvlc_meta_Language);
    info.encodedBy   = getMeta(libvlc_meta_EncodedBy);

    // 3. 更新缓存和状态
    m_mediaInfo = info;
    m_isMediaInfoAvailable = true;
}

// 静态事件回调函数（私有）
void xdgVLC::handleVlcEvent(const libvlc_event_t *p_event, void *p_user_data)
{
    // libvlc不知道C++的'this'指针，所以将它作为p_user_data传递进来。在这里，将它转换回自己的类实例指针
    xdgVLC *self = static_cast<xdgVLC*>(p_user_data);
    if (!self) return;

    // 根据事件类型，进行分发
    switch (p_event->type) {
    case libvlc_MediaParsedChanged:
    {
        int status = p_event->u.media_parsed_changed.new_status;

        if (status == libvlc_media_parsed_status_done) {
            self->processMediaMetaChanged(); // 处理元数据并通知
            emit self->mediaInfoReady();
        }
        else if (status == libvlc_media_parsed_status_failed) {
            emit self->errorOccurred("无法解析媒体文件");
        }
        break;
    }

    // --- 处理播放器事件 ---
    case libvlc_MediaPlayerPlaying:
        emit self->playing();
        break;

    case libvlc_MediaPlayerPaused:
        emit self->paused();
        break;

    case libvlc_MediaPlayerStopped:
        emit self->stopped();
        break;

    case libvlc_MediaPlayerEndReached:
        emit self->ended();
        break;

    case libvlc_MediaPlayerTimeChanged:
        emit self->timeChanged(p_event->u.media_player_time_changed.new_time); // 从事件中提取新的时间值
        break;

    case libvlc_MediaPlayerPositionChanged:
        emit self->positionChanged(p_event->u.media_player_position_changed.new_position); // 从事件中提取新的位置百分比
        break;
        // ------------------------------------
    }

}


// 清理绑的事件与m_libvlc_media_player与m_libvlc_media
void xdgVLC::cleanupPlayer()
{
    if (!m_libvlc_media_player) {
        return; // 如果已经清理过了，直接返回
    }

    // --- 采用最安全的顺序 ---

    // 1. **先解除事件绑定**
    // 立即切断VLC后台线程与我们代码的联系，避免竞态条件。
    libvlc_event_manager_t *em = libvlc_media_player_event_manager(m_libvlc_media_player);
    if(em){
        libvlc_event_detach(em, libvlc_MediaPlayerPlaying, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerPaused, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerStopped, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerEndReached, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, handleVlcEvent, this);
        libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, handleVlcEvent, this);
    }

    // 同样，清理媒体对象的事件绑定
    if (m_libvlc_media) {
        libvlc_event_manager_t *media_em = libvlc_media_event_manager(m_libvlc_media);
        if (media_em) {
            libvlc_event_detach(media_em, libvlc_MediaParsedChanged, handleVlcEvent, this);
        }
    }

    // 2. **再命令播放器停止**
    // 此时即使停止过程中产生新事件，它们也不会再被分发到我们的代码里。
    libvlc_media_player_stop(m_libvlc_media_player);

    // 3. **最后释放核心资源**
    libvlc_media_player_release(m_libvlc_media_player);
    m_libvlc_media_player = nullptr;

    if (m_libvlc_media) {
        libvlc_media_release(m_libvlc_media);
        m_libvlc_media = nullptr;
    }

    // 4. 重置状态变量
    m_isMediaInfoAvailable = false;
    m_mediaInfo = MediaInfo();
}
